<!DOCTYPE html>
<html lang="en">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>闭包的访问过程(The process of accessing a closure)</title>
  <!-- 
  在JavaScript中，闭包（Closure）是一个重要的概念，它允许函数访问其外部作用域的变量，即使外部函数已经返回。
  一、闭包的基本概念
  闭包是由一个函数及其相关的引用环境组合而成的。简单来说，闭包使得一个函数可以“记住”并访问它的外部作用域中的变量。闭包的形成通常发生在函数嵌套的情况下。

  二、访问闭包的过程
  访问闭包的过程可以分为以下几个步骤：
  1. 定义外部函数：
    - 创建一个外部函数，该函数包含一个或多个内部函数。
    function outerFunction() {
        let outerVariable = '我是外部变量';

        function innerFunction() {
            console.log(outerVariable); // 访问外部变量
        }

        return innerFunction; // 返回内部函数
    }
  2. 调用外部函数：
    - 调用外部函数并将返回的内部函数赋值给一个变量。
    const closureFunction = outerFunction(); // 调用外部函数
  3. 执行内部函数：
    - 当调用返回的内部函数时，它会访问并使用外部函数中的变量，即使外部函数已经执行完毕。
    closureFunction(); // 输出: 我是外部变量
  三、闭包的特性
  1. 持久化状态：
    - 闭包可以持久化外部函数的状态，使得内部函数能够访问这些状态。

  2. 私有变量：
    - 通过闭包，可以创建私有变量，这些变量只能通过内部函数访问，外部代码无法直接访问。

  四、闭包的应用
  1. 数据封装：
    - 使用闭包可以隐藏实现细节，只暴露必要的接口。
    function createCounter() {
        let count = 0; // 私有变量

        return {
            increment: function() {
                count += 1;
                return count;
            },
            decrement: function() {
                count -= 1;
                return count;
            },
            getCount: function() {
                return count;
            }
        };
    }

    const counter = createCounter();
    console.log(counter.increment()); // 输出: 1
    console.log(counter.increment()); // 输出: 2
    console.log(counter.getCount());  // 输出: 2
  2. 事件处理：
    - 在事件处理程序中，闭包可以保持对某些变量的引用。

  五、总结
  - 访问闭包的过程主要包括定义外部函数、调用外部函数、以及执行内部函数。
  - 闭包允许内部函数访问外部函数的变量，即使外部函数已经返回。
  - 闭包的特性包括持久化状态和私有变量，这使得它在数据封装和状态管理上非常有用。
   -->
</head>
<body>

  <script>
    // 1. 定义外部函数
    function createAdder(count) {
      function adder(num) {
        return count + num
      }

      return adder
    }

    var adder5 = createAdder(5)
    adder5(100)
    adder5(55)
    adder5(12)

    var adder8 = createAdder(8)
    adder8(22)
    adder8(35)
    adder8(7)

    console.log(adder5(24))
    console.log(adder8(30))

    // 永远不会再使用adder8
    // 内存泄漏: 对于那些我们永远不会再使用的对象, 但是对于GC来说, 它不知道要进行释放的对应内存会依然保留着, 这就造成了内存泄漏

    // 2. 调用外部函数
    function createCounter() {
        let count = 0; // 私有变量

        return {
            increment: function() {
                count += 1;
                return count;
            },
            decrement: function() {
                count -= 1;
                return count;
            },
            getCount: function() {
                return count;
            }
        };
    }

    const counter = createCounter();
    console.log(counter.increment()); // 输出: 1
    console.log(counter.increment()); // 输出: 2
    console.log(counter.getCount());  // 输出: 2
    
  </script>
  
</body>
</html>